package cn.wolf.sqlite.dao.impl;

import java.lang.reflect.Field;
import java.sql.Blob;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import cn.wolf.sqlite.anotation.Column;
import cn.wolf.sqlite.anotation.Id;
import cn.wolf.sqlite.anotation.Table;
import cn.wolf.sqlite.dao.BaseDao;
import cn.wolf.sqlite.util.TableHelper;
import cn.wolf.tools.Log;

/**
 * AHibernate概要 <br/>
 * (一)支持功能: 1.自动建表,支持属性来自继承类:可根据注解自动完成建表,并且对于继承类中的注解字段也支持自动建表. 2.自动支持增删改
 * ,增改支持对象化操作:增删改是数据库操作的最基本单元,不用重复写这些增删改的代码,并且添加和更新支持类似于hibernate中的对象化操作.
 * 3.查询方式灵活:支持android框架提供的方式,也支持原生sql方式.
 * 4.查询结果对象化:对于查询结果可自动包装为实体对象,类似于hibernate框架.
 * 5.查询结果灵活:查询结果支持对象化,也支持结果为List<Map<String,String>>形式,这个方法在实际项目中很实用,且效率更好些.
 * 6.日志较详细:因为android开发不支持热部署调试,运行报错时可根据日志来定位错误,这样可以减少运行Android的次数. <br/>
 * (二)不足之处: <br/>
 * 1.id暂时只支持int类型,不支持uuid,在sqlite中不建议用uuid.
 * 2.现在每个方法都自己开启和关闭事务,暂时还不支持在一个事务中做多个操作然后统一提交事务. <br/>
 */
public class BaseDaoImpl<T> implements BaseDao<T> {
	private SQLiteOpenHelper dbHelper;
	private String tableName;
	private String idColumn;
	private Class<T> clazz;
	private List<Field> allFields;

	@SuppressWarnings("unchecked")
	public BaseDaoImpl(SQLiteOpenHelper dbHelper) {
		this.dbHelper = dbHelper;

		this.clazz = ((Class<T>) ((java.lang.reflect.ParameterizedType) super.getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0]);

		if (this.clazz.isAnnotationPresent(Table.class)) {
			Table table = (Table) this.clazz.getAnnotation(Table.class);
			this.tableName = table.name();
		}

		//
		this.allFields = TableHelper.joinFields(this.clazz.getDeclaredFields(), this.clazz
				.getSuperclass().getDeclaredFields());

		//
		for (Field field : this.allFields) {
			if (field.isAnnotationPresent(Id.class)) {
				Column column = (Column) field.getAnnotation(Column.class);
				this.idColumn = column.name();
				break;
			}
		}

		Log.d("clazz:" + this.clazz + " tableName:" + this.tableName + " idColumn:" + this.idColumn);
	}

	public SQLiteOpenHelper getDbHelper() {
		return dbHelper;
	}

	/**
	 * 通过实体ID获取实体类
	 * @param id
	 *   	实体ID
	 * @return	T
	 * 		实体类
	 */
	public T get(int id) {
		String selection = this.idColumn + " = ?";
		String[] selectionArgs = { Integer.toString(id) };
		Log.d("[get]: select * from " + this.tableName + " where " + this.idColumn + " = '" + id
				+ "'");
		List<T> list = find(null, selection, selectionArgs, null, null, null, null);
		if ((list != null) && (list.size() > 0)) {
			return (T) list.get(0);
		}
		return null;
	}

	/**
	 * 执行Sql语句
	 * @param sql
	 * 		Sql语句
	 * @param selectionArgs
	 * 		Sql语句的相关参数，数组
	 * @return	List<T>
	 * 		返回的列表数据
	 */
	public List<T> rawQuery(String sql, String[] selectionArgs) {
		Log.d("[rawQuery]: " + sql);

		List<T> list = new ArrayList<T>();
		SQLiteDatabase db = null;
		Cursor cursor = null;
		try {
			db = this.dbHelper.getReadableDatabase();
			cursor = db.rawQuery(sql, selectionArgs);

			getListFromCursor(list, cursor);
		} catch (Exception e) {
			Log.e("[rawQuery] from DB Exception.");
			e.printStackTrace();
		} finally {
			if (cursor != null) {
				cursor.close();
			}
			if (db != null) {
				db.close();
			}
		}

		return list;
	}

	/**
	 * 判断相关数据是否存在
	 * @param sql
	 * 		SQL语句
	 * @param selectionArgs
	 * 		SQL语句的相关参数，数组
	 * @return	boolean
	 * 		返回是否存在，boolean类型
	 */
	public boolean isExist(String sql, String[] selectionArgs) {
		Log.d("[isExist]: " + sql);

		SQLiteDatabase db = null;
		Cursor cursor = null;
		try {
			db = this.dbHelper.getReadableDatabase();
			cursor = db.rawQuery(sql, selectionArgs);
			if (cursor.getCount() > 0) {
				return true;
			}
		} catch (Exception e) {
			Log.e("[isExist] from DB Exception.");
			e.printStackTrace();
		} finally {
			try {
				if (cursor != null) {
					cursor.close();
				}
				if (db != null) {
					db.close();
				}
			} catch (Exception e) {
				Log.e("[isExist] from DB Exception." + e.getMessage());
			}
		}
		return false;
	}

	/**
	 * 获取所有的数据
	 * @return List<T>
	 * 		返回的所有数据，以列表返回
	 */
	public List<T> find() {
		return find(null, null, null, null, null, null, null);
	}

	/**
	 * 自定义获取数据
	 * @param columns
	 * 		列
	 * @param selection
	 * 		
	 * @param selectionArgs
	 * 		变量
	 * @param groupBy
	 * 		eg：group by
	 * @param having
	 * 		eg：having xxx
	 * @param orderBy
	 * 		eg：order by 顺序
	 * @param limit
	 * 		eg：limit 限制
	 * @return List<T>
	 * 		返回的数据列表
	 */
	public List<T> find(String[] columns, String selection, String[] selectionArgs, String groupBy,
			String having, String orderBy, String limit) {
		Log.d("[find]");

		List<T> list = new ArrayList<T>();
		SQLiteDatabase db = null;
		Cursor cursor = null;
		try {
			db = this.dbHelper.getReadableDatabase();
			cursor = db.query(this.tableName, columns, selection, selectionArgs, groupBy, having,
					orderBy, limit);

			getListFromCursor(list, cursor);
		} catch (Exception e) {
			Log.e("[find] from DB Exception");
			e.printStackTrace();
		} finally {
			if (cursor != null) {
				cursor.close();
			}
			if (db != null) {
				db.close();
			}
		}

		return list;
	}

	/**
	 * 通过Cursor获取数据列表
	 * @param list
	 * 		实体类列表
	 * @param cursor
	 * 		数据库的游标
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	private void getListFromCursor(List<T> list, Cursor cursor) throws IllegalAccessException,
			InstantiationException {
		while (cursor.moveToNext()) {
			T entity = this.clazz.newInstance();

			for (Field field : this.allFields) {
				Column column = null;
				if (field.isAnnotationPresent(Column.class)) {
					column = (Column) field.getAnnotation(Column.class);

					field.setAccessible(true);
					Class<?> fieldType = field.getType();

					int c = cursor.getColumnIndex(column.name());
					if (c < 0) {
						continue; // ������ѭ���¸�����ֵ
					} else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
						field.set(entity, cursor.getInt(c));
					} else if (String.class == fieldType) {
						field.set(entity, cursor.getString(c));
					} else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
						field.set(entity, Long.valueOf(cursor.getLong(c)));
					} else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
						field.set(entity, Float.valueOf(cursor.getFloat(c)));
					} else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {
						field.set(entity, Short.valueOf(cursor.getShort(c)));
					} else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
						field.set(entity, Double.valueOf(cursor.getDouble(c)));
					} else if (Blob.class == fieldType) {
						field.set(entity, cursor.getBlob(c));
					} else if (Character.TYPE == fieldType) {
						String fieldValue = cursor.getString(c);

						if ((fieldValue != null) && (fieldValue.length() > 0)) {
							field.set(entity, Character.valueOf(fieldValue.charAt(0)));
						}
					}
				}
			}

			list.add((T) entity);
		}
	}

	/**
	 * 插入实体类数据
	 * @param T
	 *  	实体泛型类
	 * @return long
	 * 		the row ID of the newly inserted row, or -1 if an error occurred
	 */
	public long insert(T entity) {
		Log.d("[insert]: inset into " + this.tableName + " " + entity.toString());
		SQLiteDatabase db = null;
		try {
			db = this.dbHelper.getWritableDatabase();
			ContentValues cv = new ContentValues();
			setContentValues(entity, cv, "create");
			long row = db.insert(this.tableName, null, cv);
			return row;
		} catch (Exception e) {
			Log.d("[insert] into DB Exception.");
			e.printStackTrace();
		} finally {
			if (db != null) {
				db.close();
			}
		}

		return 0L;
	}

	/**
	 * 通过ID删除相关的数据
	 * @param id 
	 * 		实体ID
	 */
	public void delete(int id) {
		SQLiteDatabase db = this.dbHelper.getWritableDatabase();
		String where = this.idColumn + " = ?";
		String[] whereValue = { Integer.toString(id) };

		Log.d("[delete]: delelte from " + this.tableName + " where "
				+ where.replace("?", String.valueOf(id)));

		db.delete(this.tableName, where, whereValue);
		db.close();
	}

	/**
	 * 通过多个ID删除相关实体类
	 * @param ids
	 * 		可变参数，多个ID
	 */
	public void delete(Integer... ids) {
		if (ids.length > 0) {
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < ids.length; i++) {
				sb.append('?').append(',');
			}
			sb.deleteCharAt(sb.length() - 1);
			SQLiteDatabase db = this.dbHelper.getWritableDatabase();
			String sql = "delete from " + this.tableName + " where " + this.idColumn + " in (" + sb
					+ ")";

			Log.d("[delete]: " + sql);

			db.execSQL(sql, (Object[]) ids);
			db.close();
		}
	}
	
	@Override
	public void deleteAll() {
		SQLiteDatabase db = this.dbHelper.getWritableDatabase();
		String sql = "delete from " + this.tableName ;

		Log.d("[delete]: " + sql);

		db.execSQL(sql, new String[]{});
		db.close();
	}

	/**
	 * 修改实体类数据
	 * @param T
	 * 		相应实体类
	 */
	public void update(T entity) {
		SQLiteDatabase db = null;
		try {
			db = this.dbHelper.getWritableDatabase();
			ContentValues cv = new ContentValues();

			setContentValues(entity, cv, "update");

			String where = this.idColumn + " = ?";
			int id = Integer.parseInt(cv.get(this.idColumn).toString());
			cv.remove(this.idColumn);

			Log.d("[update]: update " + this.tableName + " where "
					+ where.replace("?", String.valueOf(id)));

			String[] whereValue = { Integer.toString(id) };
			db.update(this.tableName, cv, where, whereValue);
		} catch (Exception e) {
			Log.d("[update] DB Exception.");
			e.printStackTrace();
		} finally {
			if (db != null)
				db.close();
		}
	}

	private void setContentValues(T entity, ContentValues cv, String type)
			throws IllegalAccessException {

		for (Field field : this.allFields) {
			if (!field.isAnnotationPresent(Column.class)) {
				continue;
			}
			Column column = (Column) field.getAnnotation(Column.class);

			field.setAccessible(true);
			Object fieldValue = field.get(entity);
			if (fieldValue == null)
				continue;
			if (("create".equals(type)) && (field.isAnnotationPresent(Id.class))) {
				continue;
			}
			cv.put(column.name(), fieldValue.toString());
		}
	}

	/**
	 * 查询数据并返回MAP数据
	 * @param sql
	 * 		SQL语句
	 * @param selectionArgs
	 * 		相关参数
	 * @return	List<Map<String, String>>
	 * 		返回的数据，列表显示的Map
	 */
	public List<Map<String, String>> query2MapList(String sql, String[] selectionArgs) {
		Log.d("[query2MapList]: " + sql);
		SQLiteDatabase db = null;
		Cursor cursor = null;
		List<Map<String, String>> retList = new ArrayList<Map<String, String>>();
		try {
			db = this.dbHelper.getReadableDatabase();
			cursor = db.rawQuery(sql, selectionArgs);
			while (cursor.moveToNext()) {
				Map<String, String> map = new HashMap<String, String>();
				for (String columnName : cursor.getColumnNames()) {
					map.put(columnName.toLowerCase(),
							cursor.getString(cursor.getColumnIndex(columnName)));
				}
				retList.add(map);
			}
		} catch (Exception e) {
			Log.e("[query2MapList] from DB exception");
			e.printStackTrace();
		} finally {
			if (cursor != null) {
				cursor.close();
			}
			if (db != null) {
				db.close();
			}
		}

		return retList;
	}

	/**
	 * 执行SQL语句
	 * 
	 * @param sql
	 * 		SQL语句
	 * @param selectionArgs
	 * 		相关参数
	 */
	public void execSql(String sql, Object[] selectionArgs) {
		SQLiteDatabase db = null;
		Log.d("[execSql]: " + sql);
		try {
			db = this.dbHelper.getWritableDatabase();
			if (selectionArgs == null) {
				db.execSQL(sql);
			} else {
				db.execSQL(sql, selectionArgs);
			}
		} catch (Exception e) {
			Log.e("[execSql] DB exception.");
			e.printStackTrace();
		} finally {
			if (db != null) {
				db.close();
			}
		}
	}
}